import {
    ArcGisMapServerImageryProvider,
    WebMapTileServiceImageryProvider,
} from 'cesium'
import * as Cesium from "cesium";
import SuperGif from "libgif";
import defaultImage from "@/assets/img/location.png";
import {getAssetsFile} from "@/utils/utils";

/**
 * 加载arcgis server的数据服务,cesium@1.115.0 写法改变
 * @param viewer
 */
const loadArcgisServer = async (viewer: any) => {
    let esrilayer = await ArcGisMapServerImageryProvider.fromUrl("https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
    viewer.imageryLayers.addImageryProvider(esrilayer)
}
/**
 * 加载天地图
 * @param viewer
 * @param type
 */
const loadTdtLayer = (viewer: any, type: string, isAnHei: boolean = false) => {
    viewer.imageryLayers.removeAll();
    const tdtKeys = [
        '18992e1edf6d198f398c38c5eee5aad9',
        '452fa1da60ebc9ea7c09702678f1fb96',
        'f50150db8ad49aec65c54db85d313a85',
        '576ab0b068f9559271b1c8cc65653384',
        'c57ca7cce19c08cf8d982bfddf581ccf',
        'f424a5e7adbe5c596ff4013c9e437ce9']
    let num = Math.floor(Math.random() * (5 - 1) + 1);
    let currentKeys = tdtKeys[num];
    //在线天地图影像服务地址(墨卡托投影)
    var TDT_IMG_W = "http://{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default&format=tiles&tk=" + currentKeys;
    //在线天地图矢量地图服务(墨卡托投影)
    var TDT_VEC_W = "http://{s}.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default&format=tiles&tk=" + currentKeys;
    //在线天地图影像中文标记服务(墨卡托投影)
    var TDT_CIA_W = "http://{s}.tianditu.gov.cn/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default.jpg&tk=" + currentKeys
    //在线天地图矢量中文标记服务(墨卡托投影)
    var TDT_CVA_W = "http://{s}.tianditu.gov.cn/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default.jpg&tk=" + currentKeys;
    //在线天地图地形地图服务(墨卡托投影)
    var TDT_TER_W = "http://{s}.tianditu.gov.cn/ter_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=ter&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default.jpg&tk=" + currentKeys;
    //在线天地图地形中文标记服务(墨卡托投影)
    var TDT_CTA_W = "http://{s}.tianditu.gov.cn/cta_w/wmts?service=wmts&request=GetTile&version=1.0.0" +
        "&LAYER=cta&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
        "&style=default.jpg&tk=" + currentKeys;
    let mapUrl = TDT_IMG_W;
    let labelUrl = TDT_CIA_W;
    if (type === 'c') {
        // 影像图
        mapUrl = TDT_IMG_W;
        labelUrl = TDT_CIA_W;
    } else if (type === 'w') {
        // 矢量图
        mapUrl = TDT_VEC_W;
        labelUrl = TDT_CVA_W;
    } else if (type === 'd') {
        // 地形图
        mapUrl = TDT_TER_W;
        labelUrl = TDT_CTA_W;
    }
    let Img = new WebMapTileServiceImageryProvider({
        //调用影像中文服务
        url: mapUrl,
        //WMTS请求的层名称
        layer: "ter_w",
        //WMTS请求的样式名称
        style: "default",
        //MIME类型，用于从服务器检索图像
        format: "image/jpeg",
        //用于WMTS请求的TileMatrixSet的标识符
        tileMatrixSetID: "GoogleMapsCompatible",
        //天地图8个服务器
        subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
        minimumLevel: 0,
        maximumLevel: 18,
    })
    let images = viewer.imageryLayers.addImageryProvider(Img)
    if (isAnHei) {
        //图层的色调
        images.hue = 3;
        //图层对比度
        images.contrast = -1.2
    }
    // images.brightness=0.4
    //调用影像中文注记服务
    let cia = new WebMapTileServiceImageryProvider({
        url: labelUrl,
        layer: "cta_w",
        style: "default",
        format: "tiles",
        tileMatrixSetID: "GoogleMapsCompatible",
        subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
        minimumLevel: 0,
        maximumLevel: 18,
    })
    viewer.imageryLayers.addImageryProvider(cia)
}

/**
 * 加载gltf/glb模型数据
 * @param viewer
 * @param url
 * @param jwd
 */
const loadGltf = (viewer: any, url: string, jwd: [number, number, number], isTracked: boolean = true) => {
    let position = Cesium.Cartesian3.fromDegrees(jwd[0], jwd[1], jwd[2]);
    const heading = Cesium.Math.toRadians(135);
    const pitch = 0;
    const roll = 0;
    const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(
        position,
        hpr
    );
    const entity = viewer.entities.add({
        position: position,
        orientation: orientation,
        model: {
            uri: url,
            minimumPixelSize: 128,
            maximumScale: 20000,
        },
    });
    if (isTracked) {
        viewer.trackedEntity = entity;
    }
    return entity;
}

/**
 * 加载倾斜摄影的数据模型
 * @param viewer
 * @param url  http://ip:port/xxx/
 * @param layerCode
 * @param option  {
 *   "spaceError":16，屏幕空间错误 默认16，越小模型越精细，加载效率越低，越大模型粗，加载效率快
 *   "height":0,调整模型的高，默认0
 *   "offset":{
 *     "tx":109.xx, 中心位置 经度
 *     "ty":32.xx, 中心位置  纬度
 *     "tz":100.xx，中心位置高度
 *     "rx":32, X轴（经度）方向旋转角度（单位：度）
 *     "ry":32,Y轴（纬度）方向旋转角度（单位：度）
 *     "rz":32 Z轴（高程）方向旋转角度（单位：度）
 *   }， 模型旋转参数
 *   "bLocTo":true | false,是否加载后定位
 * }
 * @creeate zgf
 * @date 20230526
 * @desc 原先基于cesium@1.96，需要升级基于cesium@1.115
 */
const loadModelLayer = async (viewer: any, url: any, layerCode: string, option: any) => {
    let {spaceError, height, offset, bLocTo} = option;
    if (!height) {
        height = 0;
    }
    if (!spaceError) {
        spaceError = 16;
    }
    const tileset = await Cesium.Cesium3DTileset.fromUrl(
        url, {
            maximumScreenSpaceError: spaceError,
            foveatedTimeDelay: 2,
            progressiveResolutionHeightFraction: 0.2,// 数值偏于0能够让初始加载变得模糊
            cullRequestsWhileMovingMultiplier: 10,// 值越小能够更快的剔除
            cullRequestsWhileMoving: true,   //优化选项。不要请求可能因为相机的移动而返回时未使用的磁贴
            cullWithChildrenBounds: true,  //优化选项。是否使用其子对象边界体积的联合来剔除瓷砖
            loadSiblings: true, // 如果为 true 则不会在已加载完模型后，自动从中心开始超清化模型
            immediatelyLoadDesiredLevelOfDetail: false,
            preloadWhenHidden: true,
            preferLeaves: true,

            //下面的参数要测试下影响
            // //以下四参数一起使用
            // skipLevelOfDetail: true,
            // baseScreenSpaceError: 512,//跳过细节级别之前必须达到的屏幕空间错误
            // skipScreenSpaceErrorFactor: 64,//定义要跳过的最小屏幕空间误差
            // skipLevels: 2,
            // //以下三参数一起使用
            // dynamicScreenSpaceErrorDensity: 0.8, // 数值加大，能让周边加载变快
            // dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没，反正放着吧先
            // dynamicScreenSpaceError: true, // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
            // //以下2参数一起使用
            // cacheBytes: 134217728,//目标缓存量，单位字节，默认512M=536870912，现在改为128M
            // maximumCacheOverflowBytes: 134217728,//超出缓存量，超出cacheBytes的缓存量
            // preloadFlightDestinations: false,//视角移动过程中预加载相机最终移动的目的地的磁贴

        });
    viewer.scene.primitives.add(tileset);
    if (height && height !== 0) {
        contentFun.changeHeight(height, tileset);
    }
    if (offset) {
        contentFun.translationTiles(tileset, offset);
    }
    if (bLocTo) {
        viewer.zoomTo(tileset);
    }
    viewer.scene.requestRender();
    return tileset;
}
/**
 * 删除所有图层-谨慎使用
 * @param viewer
 */
const removeAllLayer = (viewer: any) => {
    let flag: boolean = false;
    try {
        //移除所有的dataSources
        viewer.dataSources.removeAll();
        //移除所有的imageLayers
        viewer.imageryLayers.removeAll();
        //移除所有的primitives
        viewer.scene.primitives.removeAll();
        flag = true;
    } catch (e) {
        flag = false;
        return flag;
    }
    return flag;
}
/**
 * 根据ID删除图层
 * @param viewer
 * @param layerCode
 */
const removeLayer = (viewer: any, layerCode: string) => {
    //删除dataSources
    let list = viewer.dataSources._dataSources;
    if (list.length > 0) {
        let item = list.find((item: any) => {
            return item.name === layerCode;
        });
        if (item) {
            viewer.dataSources.remove(item);
            return true;
        }
    }
    //判断是否是ImageLayers
    let wmslayers = viewer.imageryLayers._layers;
    if (wmslayers.length > 0) {
        let sitem = wmslayers.find((sitem: any) => {
            //从1.96升级1.115后，原先的参数_layer 变为_layers
            let name = sitem._imageryProvider['_layers'];
            if (name) {
                return name === layerCode;
            }
        });
        if (sitem) {
            viewer.imageryLayers.remove(sitem);
            return true;
        }
    }
    //删除model
    let collection = viewer.scene.primitives;
    let len = collection.length;
    let primitive = null;
    for (let i = 0; i < len; i++) {//删除全部tilesets
        let pri = collection.get(i);
        if (pri._url.indexOf(layerCode) >= 0) {
            primitive = pri;
            break;
        }
    }
    if (primitive) {
        viewer.scene.primitives.remove(primitive);
        return true;
    }
    return false;
}

/**
 * 提升或者降低图层的层级
 * @param viewer
 * @param layer
 * @param upOrDown
 */
const upDownLayerLevel = (viewer: any, layer: any, upOrDown: string) => {
    let state: boolean = false;
    if (layer instanceof Cesium.ImageryProvider) {
        if (upOrDown === 'up') {
            viewer.imageryLayers.raiseToTop(layer);
        } else {
            viewer.imageryLayers.lowerToBottom(layer);
        }
        state = true;
    } else if (layer instanceof Cesium.GeoJsonDataSource) {
        if (upOrDown === 'up') {
            viewer.dataSources.raiseToTop(layer);
        } else {
            viewer.dataSources.lowerToBottom(layer);
        }
        state = true;
    } else {
        state = false;
    }
    return state;
}

/**
 * 根据ID获取图层
 * @param viewer
 * @param layerCode
 */
const getLayer = (viewer: any, layerCode: string) => {
    //判断是否是DataSources
    let list = viewer.dataSources._dataSources;
    if (list.length > 0) {
        let item = list.find((item: any) => {
            return item.name === layerCode;
        });
        if (item) {
            return item;
        }
    }
    //判断是否是ImageLayers
    let wmslayers = viewer.imageryLayers._layers;
    if (wmslayers.length > 0) {
        let sitem = wmslayers.find((sitem: any) => {
            let name = sitem._imageryProvider['_layers'];
            if (name) {
                return name === layerCode;
            }
        });
        if (sitem) {
            return sitem;
        }
    }
    //判断是否是tiles的模型
    let collection = viewer.scene.primitives;
    let len = collection.length;//scene中图元数量
    let primitive = null;
    for (let i = 0; i < len; i++) {//删除全部tilesets
        let pri = collection.get(i);
        if (pri._url.indexOf(layerCode) >= 0) {
            primitive = pri;
            break;
        }
    }
    if (primitive) {
        return primitive;
    }
    return false;
}
/**
 * 添加geoserver的wms的服务
 * @param viewer
 * @param layerCode   "WorkSpace:Code"   eg:"ChangZhou:country_non_house"
 * @param url   "http://ip:port/geoserver/wms",
 * @param option {
 *  style:"",
 *  filter:""
 * }
 */
const loadImageLayer = (viewer: any, layerCode: string, url: string, option: any = {}) => {
    let {style, filter} = option;
    let params = {
        service: 'WMS',
        format: 'image/png',
        transparent: true,
    };
    if (style) {
        Object.assign(params, {
            style: style,
        });
    }
    //filter 没遇到过暂时预留
    if (filter) {
    }
    let provider = new Cesium.WebMapServiceImageryProvider({
        url: url,
        layers: layerCode,
        parameters: params,
    });
    // 从1.96 升级到 1.115 后 imagelayer的添加方式改变了
    const imageryLayer = new Cesium.ImageryLayer(provider);
    viewer.imageryLayers.add(imageryLayer);
    viewer.scene.requestRender();
    return imageryLayer;
}
/**
 * 添加geojson的数据格式的数据
 * @param viewer
 * @param layerCode  "WorkSpace:Code"   eg:"ChangZhou:country_non_house"
 * @param jsonData geojson 的格式的数据
 * @param option {
 * "style":{
 *     "pointStyle":{ "iconFont":图标,"iconsize":比率（0-1）(单位：px)  },
 *     "polygonStyle":{"color":"","strokencolor":"","strokenwidth":1,"opacity":"填充透明度"},
 *     "lineStyle":{"color":"边颜色","width":"宽度"}
 * },
 * "filter":"",   需要属性过滤的图层
 * "type":"Point/Polyline/Polygon"
 * }
 * @create zgf
 * @date 20230526
 */
const loadDataSourcesLayer = (viewer: any, layerCode: string, jsonData: any, option: any) => {
    // let { result, style, type, mapIcon, filter, layerCode } = options;
    let {style, filter, type} = option;
    console.log(layerCode);
    // let data = result;
    //因为坐标系 4490，需要重新定义geojson的格式
    let json = {
        'type': 'FeatureCollection',
        'features': jsonData.features,
    };
    let newStyle: any = null;
    let strokeColor: any = null;
    let img: string = defaultImage,
        imageSize: number = 0.4,
        strokenColor: string = '#00FFFF',
        strokenWidth: number = 3,
        fillColor: string = '#00FFFF',
        fillOpacity: number = 1;
    if (style) {
        let {pointStyle, polygonStyle, lineStyle} = style;
        if (pointStyle) {
            img = pointStyle?.iconFont ? pointStyle['iconFont'] : defaultImage;
            imageSize = pointStyle?.iconsize ? pointStyle['iconsize'] : 1;
        }
        if (polygonStyle) {
            fillColor = polygonStyle?.color ? polygonStyle['color'] : '#00FFFF';
            fillOpacity = polygonStyle?.opacity ? polygonStyle.opacity : 0.4;
            strokenColor = polygonStyle?.strokencolor ? polygonStyle['strokencolor'] : '#00FFFF';
            strokenWidth = polygonStyle?.strokenwidth ? polygonStyle['strokenwidth'] : 3;
        }
        if (lineStyle) {
            strokenColor = lineStyle?.color ? lineStyle['color'] : '#00FFFF';
            strokenWidth = lineStyle?.width ? lineStyle['width'] : 3;
        }
    }
    if (type === 'Polygon') {
        newStyle = {
            stroke: Cesium.Color.fromCssColorString(strokenColor),
            fill: Cesium.Color.fromCssColorString(fillColor).withAlpha(fillOpacity),
            strokeWidth: strokenWidth,
        };
    } else if (type === 'Polyline') {
        newStyle = {
            stroke: strokeColor,
            strokeWidth: strokenWidth,
        };
    } else if (type === 'Point') {
        newStyle = {
            markerSymbol: '?',
        };
    }
    let sourcePromise: any = null;
    if (newStyle) {
        //可以加样式，样式写法 Cesium.GeoJsonDataSource.load(json,style)
        sourcePromise = Cesium.GeoJsonDataSource.load(json, newStyle);
    } else {
        sourcePromise = Cesium.GeoJsonDataSource.load(json);
    }
    sourcePromise.then((dataSource: any) => {
        dataSource.name = layerCode;
        viewer.dataSources.add(dataSource);
        if (type === 'Point') {
            var entities = dataSource.entities.values;
            for (var i = 0; i < entities.length; i++) {
                var entity = entities[i];
                let currentScale = 0;
                entity.billboard = {
                    image: img,
                    scale: new Cesium.CallbackProperty(() => {
                        currentScale += 0.05;
                        return currentScale >= imageSize ? imageSize : currentScale;
                    }, false),
                    disableDepthTestDistance: Number.POSITIVE_INFINITY,
                    heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
                };
            }
        } else if (type === 'polygon') {

        } else if (type === 'polyline') {

        }
        viewer.scene.requestRender();
        return dataSource;
    })

}
/**
 * 加载Geoserver的服务的数据
 * @param viewer
 * @param url 实际需要  "http://ip:port/geoserver/wfs"
 * @param layerCode  "WorkSpace:Code"   eg:"ChangZhou:country_non_house"
 * @param option {
 * "style":{
 *     "pointStyle":{ "iconFont":图标,"iconsize":比率（0-1）(单位：px)  },
 *     "polygonStyle":{"color":"","strokencolor":"","strokenwidth":1,"opacity":"填充透明度"},
 *     "lineStyle":{"color":"边颜色","width":"宽度"}
 * },
 * "filter":"",   需要属性过滤的图层
 * "type":"Point/Polyline/Polygon"
 * }
 * @create zgf
 * @date 20230526
 */
const loadVectorLayer = async (viewer: any, url: string, layerCode: string, option: any) => {
    let {style, filter, type} = option;
    const param = {
        service: 'wfs',
        version: '1.0.0',
        request: 'Getfeature',
        typeName: layerCode, // 图层名称
        outputFormat: 'application/json',
    };
    if (!url) {
        return;
    }
    url = url + '/ows' + contentFun.getParamString(param, url);
    let response: any = await fetch(url, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        },
        mode: 'cors'
    });
    let result = await response.json();
    if (result) {
        let data = result;
        if (!data) {
            return;
        }
        //因为坐标系 4490，需要重新定义geojson的格式
        let json = {
            'type': 'FeatureCollection',
            'features': data.features,
        };
        let newStyle: any = null;
        let strokeColor: any = null;
        let img: string = defaultImage,
            imageSize: number = 0.4,
            strokenColor: string = '#00FFFF',
            strokenWidth: number = 3,
            fillColor: string = '#00FFFF',
            fillOpacity: number = 1;
        if (style) {
            let {pointStyle, polygonStyle, lineStyle} = style;
            if (pointStyle) {
                img = pointStyle?.iconFont || defaultImage;
                imageSize = pointStyle?.iconsize || 1;
            }
            if (polygonStyle) {
                fillColor = polygonStyle?.color ?? '#00FFFF';
                fillOpacity = polygonStyle?.opacity ?? 0.4;
                strokenColor = polygonStyle?.strokencolor ?? '#00FFFF';
                strokenWidth = polygonStyle?.strokenwidth ?? 3;
            }
            if (lineStyle) {
                strokenColor = lineStyle?.color ?? '#00FFFF';
                strokenWidth = lineStyle?.width ?? 3;
            }
        }
        if (type === 'Polygon') {
            newStyle = {
                stroke: Cesium.Color.fromCssColorString(strokenColor),
                fill: Cesium.Color.fromCssColorString(fillColor).withAlpha(fillOpacity),
                strokeWidth: strokenWidth,
            };
        } else if (type === 'Polyline') {
            newStyle = {
                stroke: strokeColor,
                strokeWidth: strokenWidth,
            };
        } else if (type === 'Point') {
            newStyle = {
                markerSymbol: '?',
            };
        }
        let sourcePromise: any = null;
        if (newStyle) {
            //可以加样式，样式写法 Cesium.GeoJsonDataSource.load(json,style)
            sourcePromise = Cesium.GeoJsonDataSource.load(json, newStyle);
        } else {
            sourcePromise = Cesium.GeoJsonDataSource.load(json);
        }
        sourcePromise.then((dataSource: any) => {
            dataSource.name = layerCode;
            viewer.dataSources.add(dataSource);
            if (type === 'Point') {
                var entities = dataSource.entities.values;
                for (var i = 0; i < entities.length; i++) {
                    var entity = entities[i];
                    let currentScale = 0;
                    entity.billboard = {
                        image: img,
                        scale: new Cesium.CallbackProperty(() => {
                            currentScale += 0.05;
                            return currentScale >= imageSize ? imageSize : currentScale;
                        }, false),
                        disableDepthTestDistance: Number.POSITIVE_INFINITY,
                        heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
                    };
                }
            } else if (type === 'polygon') {

            } else if (type === 'polyline') {

            }
            viewer.scene.requestRender();
            return dataSource;
        })
    }
}

/**
 * 添加白模
 * @param jsonArr
 * @param viewer
 * @param isZoom 是否定位
 */
const renderWhiteModel = (viewer: any, dataArr: any, isZoom: boolean = false) => {
    let json = {
        'type': 'FeatureCollection',
        'features': dataArr
    }
    let entities
    let promise = Cesium.GeoJsonDataSource.load(json, {clampToGround: true})
    promise.then(function (dataSource: any) {
        if (isZoom) {
            viewer.zoomTo(dataSource);
        }
        viewer.dataSources.add(dataSource);
        entities = dataSource.entities.values
        for (let i = 0; i < entities.length; i++) {
            let entity = entities[i]
            let lvalue = entity.properties._gd._value * 5;
            let color = '#ffffff';
            entity.polygon.name = entity.properties._name._value
            entity.polygon.fill = true
            entity.polygon.material = Cesium.Color.fromCssColorString(color)
            entity.polygon.extrudedHeight = lvalue
            entity.polygon.outline = false
            entity.polygon.outlineColor = Cesium.Color.fromCssColorString(color)
        }
    })
}

/**
 * 设置实体Entity旋转
 * @param entity
 * @param  {object} options
 * @param {object} options.position - 原始位置  eg:{"lon":113.24,"lat":21.21,"height":1}
 * @param {number} options.rotateSacle - 旋转比例   default:4
 */
const setEntityRotate = (entity: any, options: any) => {
    let {position, rotateSacle} = options;
    if (position) {
        entity.position = new Cesium.CallbackProperty(function () {
            return Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']);
        }, false);
    }
    let rotateParams = {heading: 0, pitch: 0, roll: 0}
    Object.assign(rotateParams, {scale: rotateSacle})
    entity.orientation = new Cesium.CallbackProperty(function () {
        if (rotateSacle > 0) {
            rotateParams.heading += rotateSacle;
            if (rotateParams.heading === 360) {
                rotateParams.heading = 0;
            }
        }
        return Cesium.Transforms.headingPitchRollQuaternion(
            Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']),
            new Cesium.HeadingPitchRoll(
                Cesium.Math.toRadians(rotateParams.heading),
                Cesium.Math.toRadians(rotateParams.pitch),
                Cesium.Math.toRadians(rotateParams.roll)
            )
        );
    }, false);
}

/**
 * 实体上下浮动动画
 * @param entity
 * @param  {object} options
 * @param {object} options.position - 原始位置  eg:{"lon":113.24,"lat":21.21,"height":1}
 * @param {number} options.minHeiht - 最小高度   default:5
 * @param {number} options.maxHeiht - 最大高度  default:100
 * @param {number} options.speed - 高度  default:0.05
 */
const setEntityFloat = (entity: any, options: any) => {
    let {minHeiht, maxHeiht, speed, position} = options;
    if (!minHeiht) {
        minHeiht = 5
    }
    if (!maxHeiht) {
        maxHeiht = 100
    }
    if (!speed) {
        speed = 0.06
    }
    ;
    let flag = false;
    let bg_minHeiht = minHeiht;
    if (position) {
        entity.position = new Cesium.CallbackProperty(function () {
            if (minHeiht >= maxHeiht || minHeiht <= bg_minHeiht) {
                flag = !flag;
            }
            flag ? (minHeiht += speed) : (minHeiht -= speed);
            position.height = minHeiht;
            return Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']);
        }, false);
    }
}


/**
 * 创建动态旋转圆-使用图片做材质基底
 * @param viewer
 * @param  {object} options
 * @param {object} options.center - 中心坐标数组  eg:{"lon":113.24,"lat":21.21,"height":1}
 * @param {number} options.radius - 半径   default:800
 * @param {number} options.rotateScale - 旋转频率，越大越快  default:0.05
 * @param {number} options.height - 高度  default:1
 * @param {number} options.scale1 - 外圆缩放比例 default:1500
 * @param {number} options.scale2 - 内圆缩放比例  default:undefined
 * @param {string} options.image - 材质图片  eg:"static/data/images/Textures/circle_bg.png"
 * @desc 注：options.scale2=options.radius 旋转材质无缩放的动画
 */
const craeteDynamicCricleGraphics = (viewer: any, options: any) => {
    //默认初始化的参数
    let defaultOptions: any = {
        radius: 800,
        rotateScale: 0.05,
        height: 1,
        scale1: 1500,
        image: "texturex/circle_bg.png"
    }
    Object.assign(defaultOptions, options)
    let {center, radius, rotateScale, height, scale1, scale2, image} = defaultOptions;
    if (!center) {
        return;
    }
    let startRotation = 0;
    //创建材质
    let material = new Cesium.ImageMaterialProperty({
        image: getAssetsFile(image),
        transparent: true,
    });
    let entity: any = new Cesium.Entity();
    entity.position = new Cesium.CallbackProperty(function () {
        return Cesium.Cartesian3.fromDegrees(center['lon'], center['lat'], center['height']);
    }, false);
    entity.orientation = new Cesium.CallbackProperty(function () {
        return Cesium.Transforms.headingPitchRollQuaternion(
            Cesium.Cartesian3.fromDegrees(center['lon'], center['lat'], center['height']),
            new Cesium.HeadingPitchRoll(
                Cesium.Math.toRadians(0),
                Cesium.Math.toRadians(0),
                Cesium.Math.toRadians(0)
            )
        );
    }, false);
    let bg_scale = radius;
    let flag = false;
    let updateScalerAxis = () => {     //外圈缩放
        if (radius >= scale1 || radius <= bg_scale) {
            flag = !flag;
        }
        flag ? (radius += 2) : (radius -= 2);
    };
    let updateScalerAxis2 = () => {
        scale2 >= radius ? (radius += 2) : (radius = bg_scale);
    };
    //实质就是纹理旋转控制
    entity.ellipse = {
        material: material,
        height: height,
        semiMajorAxis: new Cesium.CallbackProperty(function () {
            return radius;
        }, false),
        semiMinorAxis: new Cesium.CallbackProperty(function () {
            return radius;
        }, false),
        stRotation: new Cesium.CallbackProperty(function () {
            if (rotateScale > 0) {
                startRotation += rotateScale;
                if (startRotation >= 360) {
                    startRotation = 0;
                }
            }
            if (scale1) updateScalerAxis();
            if (scale2) updateScalerAxis2();
            return startRotation;
        }, false),
    };
    viewer.entities.add(entity);
    return entity;
}


/**
 * 创建闪烁圆
 * @param viewer
 * @param {object} options
 * @param {object} options.position - 坐标数组  eg:{"lon":113.59,"lat":34.74,height:50}
 * @param {number} options.alp - 频率   default:1   最大值就是1
 * @param {boolean} options.flog - 显示雾气效果  default:true
 * @param {number} options.height - 高度
 * @param {number} options.semiMinorAxis - 短半轴  default:2000.0
 * @param {number} options.semiMajorAxis - 长半轴   default:2000.0
 * @desc 注：options.alp  和 options.flog 组合使用，用户控制透明底先降低还是先升高，最大值是1
 */
const craeteDynamicBlinkCircleGraphics = (viewer: any, options: any) => {
    let defaultOption: any = {
        alp: 1,
        flog: true,
        semiMinorAxis: 2000,
        semiMajorAxis: 2000,
        height: 10,
    };
    Object.assign(defaultOption, options)
    let {position, alp, flog, semiMinorAxis, semiMajorAxis, height} = defaultOption;
    if (!position) {
        return;
    }
    let entity: any = new Cesium.Entity();
    entity.position = Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']);
    entity.ellipse = {
        semiMinorAxis: semiMinorAxis || 2000.0,
        semiMajorAxis: semiMajorAxis || 2000.0,
        height: height,
        material: new Cesium.ColorMaterialProperty(
            new Cesium.CallbackProperty(function () {
                if (flog) {
                    alp = alp - 0.05;
                    if (alp <= 0) {
                        flog = false; // hide
                    }
                } else {
                    alp = alp + 0.05;
                    if (alp >= 1) {
                        flog = true; // show
                    }
                }
                return Cesium.Color.RED.withAlpha(alp);
            }, false)
        ),
    };
    viewer.entities.add(entity)
    return entity;
}


/**
 *  创建旋转圆柱
 * @function
 * @param {object} options
 * @param {object} options.position - 坐标数组  eg:{"lon":113.59,"lat":34.74,height:50}
 * @param {number} options.length - 长度  default:500  从起点位置到地面的高度
 * @param {number} options.topRadius - 顶部半径  default:500
 * @param {number} options.bottomRadius - 底部半径  default:500
 * @param {number} options.slices - 垂直分段数量   default:128
 * @param {string} options.image - 材质图片
 * 注： topRadius 和  bottomRadius 可以不一样，上小下大像倒扣的碗，上大下小像盆子
 */
const craeteRotateCylinderGraphics = (viewer: any, options: any) => {
    let defaultOptions: any = {
        length: 500,
        topRadius: 500,
        bottomRadius: 500,
        image: "file/cc2.png",
        slices: 128
    }
    Object.assign(defaultOptions, options)
    let {position, image, length, topRadius, bottomRadius, slices} = defaultOptions;
    if (!position) {
        return;
    }
    let entity: any = new Cesium.Entity();
    entity.position = Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']);
    entity.cylinder = {
        HeightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
        length: length,
        topRadius: topRadius,
        bottomRadius: bottomRadius,
        material: new Cesium.ImageMaterialProperty({
            image: getAssetsFile(image),
            transparent: true,
            repeat: {
                x: 1,
                y: -1,
            },
        }),
        slices: slices,
    };
    viewer.entities.add(entity);
    setEntityRotate(entity, {
        position: position,
        rotateSacle: 4,
    });
}


/**
 * 创建旋转面-可以在面的环上放各种图片
 * @function
 * @param {object} options
 * @param {Cartesian3} options.positions - 坐标数组 运动坐标数组 [[jd,wd],[jd,wd]]
 * @param {Cartesian2} options.width - 宽  200
 * @param {Cartesian2} options.height - 高  100
 * @param {string} options.image - 图片
 * @param {number} startIndex 开始运动的位置的索引
 */
const craeteRotatePlaneGraphics = (viewer: any, options: any) => {
    let {positions, image, startIndex} = options;
    if (!positions || positions.length === 0) {
        return;
    }
    let width = options['width'] || 200;
    let height = options['height'] || 150.0;
    let entity: any = new Cesium.Entity();
    let index = startIndex;
    let _position = positions[index];
    entity.position = new Cesium.CallbackProperty(function () {
        if (index == 0) {
            _position = positions[0];
            index += 1;
        } else if (index < positions.length - 1) {
            _position = positions[index];
            index += 1;

        } else if (index == positions.length - 1) {
            _position = positions[index];
            index = 0;
        }
        return _position;
    }, false);
    entity.plane = {
        // plane: new Cesium.CallbackProperty(function () {
        //     var normaB = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_center, _position, new Cesium.Cartesian3()), new Cesium.Cartesian3())
        //     _plane = new Cesium.Plane(Cesium.Cartesian3.normalize(Cesium.Cartesian3.add(normaB, _center, new Cesium.Cartesian3()), new Cesium.Cartesian3()), 0.0)
        //     _plane = Cesium.Plane.fromPointNormal(coefficients, result)
        //     return _plane;
        // }, false),
        plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Y, 0.0),
        dimensions: new Cesium.Cartesian2(width, height),
        material: new Cesium.ImageMaterialProperty({
            image: getAssetsFile(image),
        }),
    };
    return viewer.entities.add(entity);
}

/**
 *  动态渐变墙
 * @param {object} options
 * @param {Array<any>>} options.positions - 坐标数组
 * @param {number} options.alp - 透明比例 0~1
 * @param {number} options.num - 渐变步长
 * @param {number} options.speed - 速度 0~1
 * @param {object} options.color - 颜色
 * @param {string} options.image - 材质图片
 */
const craeteDynamicShadeWallGraphics = (viewer: any, options: any) => {
    let defaultOption: any = {
        alp: 1,
        num: 20,
        color: Cesium.Color.RED,
        speed: 0.003,
        image: "texturex/fence.png"
    };
    Object.assign(defaultOption, options)
    let {positions, alp, num, color, speed, image} = defaultOption;
    if (!positions || positions.length === 0) {
        return
    }
    ;
    positions = Cesium.Cartesian3.fromDegreesArrayHeights(positions)
    let wallEntity: any = new Cesium.Entity();
    wallEntity.wall = {
        positions: positions,
        material: new Cesium.ImageMaterialProperty({
            image: getAssetsFile(image),
            transparent: true,
            color: new Cesium.CallbackProperty(function () {
                if (num % 2 === 0) {
                    alp -= speed;
                } else {
                    alp += speed;
                }
                if (alp <= 0.1) {
                    num++;
                } else if (alp >= 1) {
                    num++;
                }
                return color.withAlpha(alp);
            }, false),
        }),
    };
    return viewer.entities.add(wallEntity);

}


/**
 * 视频投放
 * @function
 * @param {object} options
 * @param {object} options.position - 坐标数组  eg:{"lon":113.59,"lat":34.74,height:50}
 * @param {Cartesian2} options.height - 高
 * @param {Cartesian2} options.width - 宽
 * @param {HTMLElement} options.videoElement - video绑定dom
 * @param {Cartesian3} options.normal - 垂直方向 可选  UNIT_Z 水平  UNIT_X或者 UNIT_Y 垂直
 */
const createVideoPlaneGraphics = (viewer: any, options: any) => {
    let {position, normal, height, width} = options;
    if (normal === "v") {
        normal = Cesium.Cartesian3.UNIT_X;
    } else if (normal === "h") {
        normal = Cesium.Cartesian3.UNIT_Z;
    } else {
        normal = Cesium.Cartesian3.UNIT_Y;
    }
    if (!position) {
        return;
    }
    let entity: any = new Cesium.Entity();
    entity.position = Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']);
    entity.plane = {
        plane: new Cesium.Plane(normal, 0.0),
        dimensions: new Cesium.Cartesian2(width || 200, height || 150.0),
        material: new Cesium.ImageMaterialProperty({
            image: options.videoElement,
        }),
    };
    return viewer.entities.add(entity);
}


/**
 * gif 图片投影
 * @param {object} options
 * @param {object} options.position - 坐标 eg:{"lon":113.59,"lat":34.74,height:50}
 * @param {string} options.url - gif 的内容 或者 gif的路径，gif放public下
 * @param {Cartesian3} options.scale - 放大倍数
 * @desc 注：因为是一帧帧的遍历，gif应该尽可能的小最好500k左右不要超过1M,创建数量也应少
 */
const createGifBillboardGraphics = (viewer: any, options: any) => {
    let {position, url, scale, width, height} = options;
    if (!position) {
        return;
    }
    let gif: Array<any> = [];
    let i = 0;
    let speed = 6;
    // 遍历gif的每一帧
    const parseGifImages = function (url: string, imageArr: Array<any>, callback: any) {
        let img = document.createElement("img");
        img.src = url;
        img.setAttribute("rel:animated_src", url); // gif库需要img标签配置下面两个属性
        img.setAttribute("rel:auto_play", "0");
        document.body.appendChild(img);
        // 新建gif实例
        let rub = new SuperGif({
            gif: img,
        });
        rub.load(() => {
            for (let i = 1; i <= rub.get_length(); i++) {
                rub.move_to(i); // 遍历gif实例的每一帧
                imageArr.push(rub.get_canvas().toDataURL());
            }
            if (callback) {
                callback(imageArr)
            }
        });
    };

    parseGifImages(url, gif, (res: any) => {
        return viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(position['lon'], position['lat'], position['height']),
            billboard: {
                verticalOrigin: Cesium.VerticalOrigin.BASELINE,
                image: new Cesium.CallbackProperty(function () {
                    if (gif.length) {
                        // 解析每一帧
                        if (i < speed * (gif.length - 1)) {
                            i++;
                        } else {
                            i = 0;
                        }
                        return gif[Math.floor(i / speed)];
                    } else {
                        return url; //因为loadGif是异步的，在解析完成之前先使用原图
                    }
                }, false),
                scale: scale || 1.2,
            },
        });
    });
}

/**
 * 创建点信息
 * @function
 * @param {object} options
 * @param {Array} options.dataJson - 数据数组
 * [  {    geometry:[jd,wd,height],property:{"name":"名称",id:"",text:""}  }  ]
 * @param {boolean} options.pointConfig - 单点的样式配置
 * { color:"#ffffff",pixelSize:5,outlineColor:"#ffffff" ,outlineWidth:1 }
 * @param {object} options.billboardConfig - 绘制billboard图形的参数
 * {image:'图片路径',width:35,height:35,scale:1,pixelOffset:{x:0,y:-20},distanceDisplay:{min:100,max:1000} }
 * @param {object} options.labelConfig - 绘制label图形的参数
 * {fillColor:"#ffffff",outlineWidth:2,showBackground:true/false,backgroundColor:"#ffffff",pixelOffset:{x:0,y:-20},fontSize:14 }
 */
const createPointsGraphics = (viewer: any, options: any) => {
    let {dataJson, pointConfig, billboardConfig, labelConfig} = options;
    if (!dataJson || dataJson.length === 0) {
        return;
    }
    let points: any = [];
    dataJson.forEach((item: any) => {
        //format:[jd,wd,height]
        let geometry = item['geometry'];
        let property = item['property'];
        let entity: any = new Cesium.Entity();
        entity.name = property['name'];
        entity.oid = property['id'];
        entity.position = Cesium.Cartesian3.fromDegrees(geometry[0], geometry[1], geometry[2]);
        if (pointConfig) {
            //单点样式存在
            let {color, pixelSize, outlineColor, outlineWidth} = pointConfig;
            entity.point = new Cesium.PointGraphics({
                color: Cesium.Color.fromCssColorString(color || '#90EE90') ,
                pixelSize: pixelSize || 5,
                outlineColor: outlineColor || Cesium.Color.WHITE,
                outlineWidth: outlineWidth || 1,
            });
        }
        if (billboardConfig) {
            //图片的样式存在
            let {image, width, height, scale, pixelOffset, distanceDisplay} = billboardConfig;
            if(!pixelOffset){pixelOffset={x:0,y:15}}
            if(!distanceDisplay){ distanceDisplay={ min:10,max:30000000000 } }
            entity.billboard = new Cesium.BillboardGraphics({
                image: getAssetsFile(image || 'map_marker/bb1.png'),
                width: width || 200,
                height: height || 125,
                // clampToGround: clampToGround || true,
                scale: scale || 1,
                // eyeOffset :new Cesium.Cartesian2(0, -20),
                pixelOffset:  new Cesium.Cartesian2(pixelOffset['x'] , pixelOffset['y'] ) ,
                //最小距离，最大距离
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(distanceDisplay['min'], distanceDisplay['max'])
            });
        }
        if (labelConfig) {
            //文字样式
            let {fillColor, outlineWidth, showBackground, backgroundColor, pixelOffset,fontSize} = labelConfig;
            if(!pixelOffset){pixelOffset={x:0,y:-20}}
            let text = property['text'];
            entity.label = new Cesium.LabelGraphics({
                //文字标签
                text: text,
                font: `${ fontSize || 14 }px sans-serif`,
                fillColor:Cesium.Color.fromCssColorString(fillColor|| '#FF0000'),
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                outlineWidth: outlineWidth || 2,
                showBackground: showBackground || false,
                backgroundColor: Cesium.Color.fromCssColorString(backgroundColor || '#ffffff').withAlpha(0.8),
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset:new Cesium.Cartesian2(pixelOffset['x'] , pixelOffset['y'] )
                //heightReference:Cesium.HeightReference.RELATIVE_TO_GROUND
            });
        }
        points.push(viewer.entities.add(entity));
    })

    return points;

}
/**
 * 创建渐变锥体
 * @function
 * @param {object} options
 * @param {Cartesian3} options.position - 坐标数组
 * @param {string} options.color - 颜色
 * @param {number} options.duration - 持续时长
 * @param {number} options.length - 长度
 * @param {number} options.topRadius - 顶部半径
 * @param {number} options.bottomRadius - 底部半径
 * @param {number} options.slices - 垂直分段数量
 * @see {@link module:Graphics#getCylinderGraphics|getCylinderGraphics}
 * @see {@link CircleFadeMaterialProperty|CircleFadeMaterialProperty}
 * @example
 * import { Graphics } from 'cesium_dev_kit'
 * const graphicObj = new Graphics({
 *     cesiumGlobal: Cesium,
 *     containerId: 'cesiumContainer'
 * })
 * graphicObj.graphics.createFadeCylinderGraphics({
 *      position:Cesium.Cartesian3.fromDegrees(104.081701757991, 30.627042558105988, 200),
          length:   500 / 2,
          topRadius:   130,
          bottomRadius:   20,
          color: new Cesium.Color(0, 1, 1, 0.4),
          slices: 128,
          duration:5
 * })
 * @returns {cylinder} 返回cylinder实例
 */
 const createFadeCylinderGraphics = (viewer:any,options:any)=> {
     let { position } =options;
      if(!position) {  return; }
        let entity:any = new Cesium.Entity();
        entity.position = Cesium.Cartesian3.fromDegrees(position['lon'],position['lat'],position['height']);
        options.material = new Cesium.Scene.CircleFadeMaterialProperty({
            color: options.color || Cesium.Color.fromCssColorString("#02ff00"),
            duration: options.duration || 2000,
        });
        entity.cylinder = this.getCylinderGraphics(options);

        return this._drawLayer.entities.add(entity);

}

export {
    loadTdtLayer,
    loadArcgisServer,
    loadModelLayer,
    loadImageLayer,
    loadDataSourcesLayer,
    loadVectorLayer,
    loadGltf,
    removeAllLayer,
    removeLayer,
    upDownLayerLevel,
    getLayer,
    renderWhiteModel,
    setEntityRotate,
    setEntityFloat,
    craeteDynamicCricleGraphics,
    craeteDynamicBlinkCircleGraphics,
    craeteRotateCylinderGraphics,
    craeteRotatePlaneGraphics,
    craeteDynamicShadeWallGraphics,
    createVideoPlaneGraphics,
    createGifBillboardGraphics,
    createPointsGraphics
}

/**
 * 内部的方法，主要用于旋转模型和调整模型的高度
 * @create zgf
 * @date 20230526
 */
const contentFun = {
    translationTiles: function (tileset: any, options: any) {
        let {tx, ty, tz, rx, ry, rz} = options;
        let params = {
            tx: tx, //模型中心X轴坐标（经度，单位：十进制度）
            ty: ty, //模型中心Y轴坐标（纬度，单位：十进制度）
            tz: tz, //模型中心Z轴坐标（高程，单位：米）
            rx: rx, //X轴（经度）方向旋转角度（单位：度）
            ry: ry, //Y轴（纬度）方向旋转角度（单位：度）
            rz: rz, //Z轴（高程）方向旋转角度（单位：度）
        };
        //旋转

        let mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(params.rx));
        let my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(params.ry));
        let mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(params.rz));
        let rotationX = Cesium.Matrix4.fromRotationTranslation(mx);
        let rotationY = Cesium.Matrix4.fromRotationTranslation(my);
        let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz);
        //平移
        let position = Cesium.Cartesian3.fromDegrees(params.tx, params.ty, params.tz);
        let m = Cesium.Transforms.eastNorthUpToFixedFrame(position);
        let scale = Cesium.Matrix4.fromUniformScale(1);
        // //缩放
        Cesium.Matrix4.multiply(m, scale, m);
        //旋转、平移矩阵相乘
        Cesium.Matrix4.multiply(m, rotationX, m);
        Cesium.Matrix4.multiply(m, rotationY, m);
        Cesium.Matrix4.multiply(m, rotationZ, m);
        tileset._root.transform = m;
    },

    /**
     * 修改3dtiles的高度
     * @param height
     * @param tileset
     * @returns
     */
    changeHeight: function (height: any, tileset: any) {
        height = Number(height);
        if (isNaN(height)) {
            return;
        }
        var cartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
        var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
        var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, height);
        var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
        tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
    },


    /**
     * geoserver 的wfs拼接完整的url
     * @param obj
     * @param existingUrl
     * @param uppercase
     * @returns
     */
    getParamString: function (obj: any, existingUrl: any, uppercase: any = undefined) {
        var params: any = [];
        for (var i in obj) {
            let inner = encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]);
            params.push(inner);
        }
        return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
    },
};
